package com.yc.sole.framework.redis;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.yc.sole.framework.redis.utils.SpelUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

/**
 * 缓存
 *
 * @author yizuomin
 * @date 2023/2/28 15:47
 **/
@Aspect
@Slf4j
@RequiredArgsConstructor
@Component
public class RedisCacheAspect {

    private final RedissonService redissonService;

    /**
     * 自定义缓存
     *
     * @param joinPoint j
     * @return
     * @throws Throwable t
     */
    @Around("@annotation(com.yc.sole.framework.redis.RedisCache)")
    public Object cacheAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Signature signature = joinPoint.getSignature();
        MethodSignature msg = (MethodSignature) signature;
        Object target = joinPoint.getTarget();
        Method method = target.getClass().getMethod(msg.getName(), msg.getParameterTypes());
        //通过方法获取注解
        RedisCache annotation = method.getAnnotation(RedisCache.class);
        //参数
        Object[] args = joinPoint.getArgs();
        //spel表达式
        String spel = annotation.key();
        //解析spel表达式
        String hKey = SpelUtil.analyticalSPelExpression(method, args, spel, String.class);
        //解析出来的el表达式为空或者方法参数为空 不走缓存
        if (CharSequenceUtil.isBlank(hKey) || CollUtil.isEmpty(Arrays.asList(args))) {
            return joinPoint.proceed();
        }
        //判断是否需要移除缓存
        if (annotation.remove()) {
            redissonService.hRemove(annotation.prefix(), hKey);
            return joinPoint.proceed();
        }
        //查询缓存，缓存中有直接返回，缓存中没有则将方法返回值放到缓存中
        Object obj = redissonService.hGet(annotation.prefix(), hKey);
        if (Objects.nonNull(obj)) {
            return obj;
        } else {
            Object proceed = joinPoint.proceed();
            if (Objects.nonNull(proceed)) {
                redissonService.hPut(annotation.prefix(), hKey, proceed, annotation.expireTime());
            }
            return proceed;
        }
    }
}
